<?php

namespace App\Models\Traits;

use Carbon\Carbon;
use App\Models\GoldRound;
use App\Models\GoldProduct;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Rainsens\Dinglog\Facades\Dinglog;

trait GoldRoundCacheTrait
{
	protected static string $roundsCacheKey = 'gold_storm_rounds';

	public static function sCacheKey($rid): string
	{
		return "gold_storm_round_{$rid}";
	}

	public static function sGetCache($rid)
	{
		return Redis::hGetAll(self::sCacheKey($rid));
	}

	public static function sAliveGoldProductsCacheKey($rid): string
	{
		return "alive_gold_products_in_round_{$rid}";
	}

	public static function sSoldGoldProductsCacheKey($rid): string
	{
		return "sold_gold_products_in_round_{$rid}";
	}

	public static function sPaidGoldRecordsCacheKey($rid): string
	{
		return "paid_gold_records_in_round_{$rid}";
	}

	public static function sResellGoldRecordsCacheKey($rid): string
	{
		return "resell_gold_records_in_round_{$rid}";
	}

	public static function initCache()
	{
        Log::info("========== Start clean storm cache ......");
		GoldRound::cleanAllCache();
        Log::info("========== Storm cache cleaned ......");

        Log::info("========== Start make storm cache ......");
        GoldRound::makeAllCache();
		Log::info("========== Storm cache ready ......");

        /*Dinglog::text("
        ========== 1. Storm cache cleaned ......\n
        ========== 2. Storm cache ready ......
        "
        );*/
	}

	/**
	 * Cache all gold products in all gold rounds to redis.
	 */
	public static function makeAllCache()
	{
		self::available()->each(function (GoldRound $round) {
			$round->addToCache();
            if (!$round->isTodayStormOff()) {
                $round->makeCache();
            }
		});
	}

	/**
	 * Clean all gold products cache.
	 */
	public static function cleanAllCache()
	{
		self::all()->each(function (GoldRound $round) {
			$round->cleanCache();
		});
	}

	public static function allAvailable(): Collection
	{
		$cacheKey = self::$roundsCacheKey;
		
		if (Redis::zCard($cacheKey) <= 0) return collect();

		$rounds = collect();
		$roundIds = Redis::zRange($cacheKey, 0, -1);
		foreach ($roundIds as $rid) {
			Redis::hSet(self::sCacheKey($rid), 'now', (string)now());
			$round = Redis::hGetAll(self::sCacheKey($rid));
			$round['count'] = (string)self::sAllAliveGoldProductsCacheCount($rid);
			$rounds->push($round);
		}

		return $rounds;
	}

	public static function sGetAllAliveGoldProductsCache($rid)
	{
		return Redis::sMembers(self::sAliveGoldProductsCacheKey($rid));
	}

	public static function sAllAliveGoldProductsCacheCount($rid)
	{
		return Redis::sCard(self::sAliveGoldProductsCacheKey($rid));
	}

	public static function sGetAllSoldGoldProductsCache($rid)
	{
		return Redis::sMembers(self::sSoldGoldProductsCacheKey($rid));
	}

	public static function sAllSoldGoldProductsCacheCount($rid)
	{
		return Redis::sCard(self::sSoldGoldProductsCacheKey($rid));
	}

	public static function sIsAliveGoldProductsCacheEmpty($rid): bool
	{
		return Redis::sCard(self::sAliveGoldProductsCacheKey($rid)) <= 0;
	}

	public static function extractGoldProducts($rid): Collection
	{
		$items = collect();
		$randomPids = Redis::sRandMember(self::sAliveGoldProductsCacheKey($rid), 10);

		//$randomPids = Redis::smembers(self::sAliveGoldProductsCacheKey($rid));

		//$zjrIds = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,927];
		$user =  auth('api')->user();
		$zjrArr = collect();

		foreach ($randomPids as $pid) {
			$p = Redis::hGetAll(GoldProduct::sCacheKey($pid, $rid));
			

			if((!$user || $user->id != $p['resell_user_id']) && count($items) < 6){
				//if(in_array($p['resell_user_id'],$items)){

					$items->push($p);
				//}
				
			}
			
		}

		/*if($zjrArr){
			$count = count($zjrArr);
			$numbers = range(0,$count-1);
			shuffle($numbers);
			foreach($numbers as $v){

				if(count($items) < 6){
					$items->push($zjrArr[$v]);

				}
				
			}
		}*/

		/*foreach ($randomPids as $pid) {
			$p = Redis::hGetAll(GoldProduct::sCacheKey($pid, $rid));


			if((!$user || $user->id != $p['resell_user_id']) && count($items) < 6){

				if(!in_array($p['resell_user_id'],$zjrIds)){

					$items->push($p);
				}
				//$items->push($p);
			}
			
		}*/
		return $items;
	}


	public static function checkAllCache()
	{
		self::all()->each(function (GoldRound $round) {
			self::checkCache($round);
		});
	}

	public static function checkCache(GoldRound $round)
	{
        $aliveRound = Redis::hGetAll(self::sCacheKey($round->id));
        log_info("GRound:{$round->id}", array_string($aliveRound));

		$aliveCount = self::sAllAliveGoldProductsCacheCount($round->id);
        Log::debug("===== GP Alive : {$aliveCount}");

		$soldCount = self::sAllSoldGoldProductsCacheCount($round->id);
        Log::debug("===== GP Sold: {$soldCount}");

		$goldProduct = self::extractGoldProducts($round->id)->first();
		log_info("GP Sample:", array_string($goldProduct));
	}

	public static function cachedProductsSample(): Collection
	{
		$items = collect();

		foreach (self::all() as $round) {
			$products = self::extractGoldProducts($round->id);
			$items = $items->concat($products);
		}

		return $items;
	}

    public static function sIsTodayStormOff(): bool
    {
        $offWeekdays = cs('storm')->rest_weekdays;
        if (count($offWeekdays) <= 0) return false;
        foreach ($offWeekdays as $offDay) {
            $today = Carbon::today();
            if ($offDay == 'Mon' and $today->isMonday()) {
                return true;
            } elseif ($offDay == 'Tue' and $today->isTuesday()) {
                return true;
            } elseif ($offDay == 'Wed' and $today->isWednesday()) {
                return true;
            } elseif ($offDay == 'Thu' and $today->isThursday()) {
                return true;
            } elseif ($offDay == 'Fri' and $today->isFriday()) {
                return true;
            } elseif ($offDay == 'Sat' and $today->isSaturday()) {
                return true;
            } elseif ($offDay == 'Sun' and $today->isSunday()) {
                return true;
            }
        }
        return false;
    }

    public static function sIsTomorrowStormOff(): bool
    {
        $offWeekdays = cs('storm')->rest_weekdays;
        if (count($offWeekdays) <= 0) return false;
        foreach ($offWeekdays as $offDay) {
            $tomorrow = Carbon::tomorrow();
            if ($offDay == 'Mon' and $tomorrow->isMonday()) {
                return true;
            } elseif ($offDay == 'Tue' and $tomorrow->isTuesday()) {
                return true;
            } elseif ($offDay == 'Wed' and $tomorrow->isWednesday()) {
                return true;
            } elseif ($offDay == 'Thu' and $tomorrow->isThursday()) {
                return true;
            } elseif ($offDay == 'Fri' and $tomorrow->isFriday()) {
                return true;
            } elseif ($offDay == 'Sat' and $tomorrow->isSaturday()) {
                return true;
            } elseif ($offDay == 'Sun' and $tomorrow->isSunday()) {
                return true;
            }
        }
        return false;
    }


	/*==================================================================================================================*/




	public function cacheKey(): string
	{
		return self::sCacheKey($this->id);
	}

    public function isTodayStormOff(): bool
    {
        return self::sIsTodayStormOff();
    }

    public function isTomorrowStormOff(): bool
    {
        return self::sIsTomorrowStormOff();
    }

	public function addToCache()
	{
		if ($this->is_close) return;

		$data = [
			'id' => $this->id,
			'title' => $this->title,
			'now' => null,
			'today_opened_at' => (string)$this->today_opened_at,
			'today_started_at' => (string)$this->today_started_at,
			'today_ended_at' => (string)$this->today_ended_at,
			'tomorrow_opened_at' => (string)$this->tomorrow_opened_at,
			'tomorrow_started_at' => (string)$this->tomorrow_started_at,
			'tomorrow_ended_at' => (string)$this->tomorrow_ended_at,
            'is_ending' => $this->is_ending,
            'is_today_off' => $this->isTodayStormOff(),
		];

		Redis::zAdd(self::$roundsCacheKey, $this->id, $this->id);
		Redis::hMset($this->cacheKey(), $data);

		Log::debug("GRound: {$this->id} self added to cached");
	}

	public function aliveGoldProductsCacheKey(): string
	{
		return self::sAliveGoldProductsCacheKey($this->id);
	}

	public function soldGoldProductsCacheKey(): string
	{
		return self::sSoldGoldProductsCacheKey($this->id);
	}

	public function paidGoldRecordsCacheKey(): string
	{
		return self::sPaidGoldRecordsCacheKey($this->id);
	}

	public function resellGoldRecordsCacheKey(): string
	{
		return self::sResellGoldRecordsCacheKey($this->id);
	}

	public function allAliveGoldProductsCache()
	{
		return self::sGetAllAliveGoldProductsCache($this->id);
	}

	public function makeCache()
	{
        Log::debug("Start Making GoldProducts Cache");

		GoldProduct::index($this->id)
			->each(function (GoldProduct $item) {
				$item->addToCache();
				$item->addToAliveCache();
			});
	}

	public function cleanCache()
	{
		Redis::del($this->aliveGoldProductsCacheKey());
		Redis::del($this->soldGoldProductsCacheKey());
		Redis::del($this->paidGoldRecordsCacheKey());
		Redis::del($this->resellGoldRecordsCacheKey());

		Redis::zRem(self::$roundsCacheKey, $this->id);
		Redis::del($this->cacheKey());

		Log::info("Round: {$this->id} cache cleaned");
	}
}
